using System;
using System.Collections.Generic;
using System.Text;
using System.Runtime.Serialization;
using System.IO;
using System.Runtime.Serialization.Formatters.Binary;

namespace CincinnatiLibraryCheckAvailability
{
    [Serializable]
    public class Items
    {
        private static bool needSort = false;
        private static List<LibraryItem> items = new List<LibraryItem>();
        private static List<LibraryItem> itemsMonitored = new List<LibraryItem>();
        private static Stack<LibraryItem> itemStack = new Stack<LibraryItem>();
        private static LibraryItem currentItem = null;
        private static int index = -1;
        private static int pass = 0;

        
        private static int LibItemNameComparison (LibraryItem i1, LibraryItem i2)
        {
            return i1.Title.CompareTo(i2.Title);
        }

        private static int LibItemRankComparison(LibraryItem i1, LibraryItem i2)
        {
            int value = i1.Rank.CompareTo(i2.Rank);
            if (value != 0)
                return value;
            value = i1.InList.CompareTo(i2.InList);
            if (value != 0)
                return value;
            return LibItemNameComparison(i1, i2);
        }

        public static void Sort()
        {
            items.Sort(LibItemNameComparison);
            needSort = false;
        }

        public static void Load()
        {
            Load("");
        }

        public static void Load(string directory)
        {
            if (File.Exists(directory + "Items.data"))
            {
                Stream stream = File.Open(directory + "Items.data", FileMode.Open, FileAccess.Read);
                BinaryFormatter bformatter = new BinaryFormatter();
                try
                {
                    items = (List<LibraryItem>)bformatter.Deserialize(stream);
                    // fix old format
                    foreach (LibraryItem i in items)
                    {
                        if (string.IsNullOrEmpty(i.InList))
                            i.InList = "Default";
                        foreach (ItemStatus s in i.StatusAt.Values)
                        {
                            s.Correct();
                        }
                    }
                    // populate the tree nodes.
                }
                catch (Exception e)
                {
                    string i = e.ToString();
                }
                finally { stream.Close(); }
                Sort();
                return;
            }
            if (File.Exists("URLs.txt"))
            {
                try
                {
                    StreamReader sr = new StreamReader("URLs.txt");
                    string temp;
                    while ((temp = sr.ReadLine()) != null)
                    {
                        temp = temp.Trim();
                        items.Add(new LibraryItem(temp));
                    }
                    sr.Close();
                }
                catch (Exception) { }
            }
        }

        public static void Save()
        {
            if (File.Exists("Items.data"))
            {
                string[] files = Directory.GetFiles(".", "Items.data.*.backup", SearchOption.TopDirectoryOnly);
                Array.Sort(files);
                for (int i = 0; i < (files.Length - 4); i++)
                {
                    File.Delete(files[i]);
                }
                if (new FileInfo("Items.data").Length > 1024)
                {
                    string backupName = "Items.data." + DateTime.Now.ToString("yyyy.MM.dd-HH.mm.ss.ffff") + ".backup";
                    File.Move("Items.data", backupName);
                }
            }
            Stream stream = File.Open("Items.data", FileMode.Create);
            BinaryFormatter bformatter = new BinaryFormatter();
            try
            {
                bformatter.Serialize(stream,items);
                // populate the tree nodes.
            }
            catch (Exception) { }
            finally { stream.Close(); }
            return;
        }

        public static LibraryItem Next
        {
            get
            {
                Advance();
                return currentItem;
            }
        }

        public static LibraryItem Peek
        {
            get
            {
                if (itemStack.Count > 0)
                    return itemStack.Peek();
                else
                {
                    int i = index + 1;
                    if (i >= items.Count)
                    {
                        pass++;
                        i = 0;
                        if (items.Count == 0)
                        {
                            return null;
                        }
                    }
                    return items[i];
                }
            }
        }

        public static LibraryItem Current
        {
            get { return currentItem; }
        }

        public static bool OnLastItem
        {
            get { return itemStack.Count==0 && index==itemsMonitored.Count-1; }
        }

        public static void Advance()
        {
            if (itemStack.Count > 0)
                currentItem = itemStack.Pop();
            else
            {
                lock (itemsMonitored)
                {
                    index++;
                    if (index >= itemsMonitored.Count)
                    {
                        pass %= 10;
                        if (pass == 0)
                            UpdateMonitoredItems(false);
                            //itemsMonitored = items;
                        else
                            UpdateMonitoredItems(false);
                        pass++;

                        index = 0;
                        if (itemsMonitored.Count == 0)
                        {
                            currentItem = null;
                            return;
                        }
                        if (needSort)
                            Sort();
                    }
                    currentItem = itemsMonitored[index];
                }
            }
            if (!items.Contains(currentItem))
                Advance();
        }

        public static int Count
        {
            get { return itemsMonitored.Count; }
        }

        public static int TotalCount
        {
            get { return items.Count; }
        }

        public static LibraryItem Add(string url)
        {
            LibraryItem item = new LibraryItem(url);
            if (url.StartsWith("http://catalog.cincinnatilibrary.org/uhtbin/ckey/") && !items.Contains(item))
            {
                items.Add(item);
                itemStack.Push(item);
            }
            needSort = true;
            return item;
        }

        public static void Add(LibraryItem item)
        {
            items.Add(item);
            if (item.Title == null || item.Title.Length < 0)
                itemStack.Push(item);
            needSort = true;
        }

        public static List<LibraryItem> All
        {
            get { return items; }
        }

        public static List<LibraryItem> ToBePutOnHold
        {
            get
            {
                List<LibraryItem> list = items.FindAll(i => i.PutOnHold == true && i.IsNewRelease == false);
                list.Sort(LibItemRankComparison);
                return list;
            }
        }

        public static List<LibraryItem> At(Library lib)
        {
            return items.FindAll(delegate(LibraryItem item) { return item.StatusAt.ContainsKey(lib); });
        }

        public static List<LibraryItem> AvailableAt(Library lib)
        {
            return items.FindAll(delegate(LibraryItem item) { return item.StatusAt.ContainsKey(lib) && item.StatusAt[lib].IsAvaliable; });
        }

        public static LibraryItem FromUrl(string url)
        {
            return items.Find(delegate(LibraryItem item) { return item.URL == url; });
        }

        public static bool ContainsURL(string s)
        {
            return items.Find(item => item.URL == s) != null;
        }

        public static bool ContainsTitle(string t)
        {
            return items.Find(i => i.Title == t) != null;
        }

        internal static void Restart()
        {
            index = -1;
            currentItem = items[0];
        }

        public static void Remove(string url)
        {
            if(index>=items.IndexOf(FromUrl(url)))
                index--;
            if (index < -1)
                index = -1;
            items.RemoveAll(delegate(LibraryItem item) { return item.URL == url; });
        }

        public static void UpdateMonitoredItems()
        {
            UpdateMonitoredItems(true);
        }

        public static void UpdateMonitoredItems(bool keepCurrentItem)
        {
            lock (itemsMonitored)
            {
                itemsMonitored = items.FindAll(i => i.IsNewRelease);
                            //delegate(LibraryItem item)
                            //{
                            //    foreach (Library l in Libraries.Monitored)
                            //    {
                            //        if (item.StatusAt.ContainsKey(l))
                            //            return true;
                            //    }
                            //    return false;
                            //});
                itemsMonitored.Sort(LibItemNameComparison);
                if(keepCurrentItem && items[index]!=currentItem)
                    index = itemsMonitored.IndexOf(currentItem);
            }
        }
    }
}
